package com.googlecode.kipler.container.dl.operational;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import com.googlecode.kipler.container.dl.ABox;
import com.googlecode.kipler.container.dl.Individual;
import com.googlecode.kipler.syntax.formula.SameIndividualAssertion;


/**
 * 
 * @author İnanç Seylan
 * 
 */
public class DisjointIndividualDetector {
	private ABox aBox;

	private Set<Individual> individuals;

	private Set<Individual> result;

	public static int neededInequalityAssertCount(int individualCount) {
		int result;
		if (individualCount <= 0) {
			result = individualCount;
		} else {
			int sum = 0;
			for (int i = individualCount; i > 0; i--) {
				sum += i;
			}
			result = sum - individualCount;
		}
		return result;
	}

	public DisjointIndividualDetector(ABox aBox, Set<Individual> individuals) {
		setABox(aBox);
		setIndividuals(individuals);
	}

	/**
	 * @return the aBox
	 */
	public ABox getABox() {
		return aBox;
	}

	/**
	 * @param box
	 *            the aBox to set
	 */
	public void setABox(ABox box) {
		aBox = box;
	}

	/**
	 * @return the individuals
	 */
	public Set<Individual> getIndividuals() {
		return individuals;
	}

	/**
	 * @param individuals
	 *            the individuals to set
	 */
	public void setIndividuals(Set<Individual> individuals) {
		this.individuals = individuals;
	}

	/**
	 * @return the result
	 */
	public Set<Individual> getResult() {
		return result;
	}

	public Set<Set<Individual>> getAllSets() {
		Set<Set<Individual>> allDisjointIndividualSets = new HashSet<Set<Individual>>();
		for (Individual indv1 : getIndividuals()) {
			boolean addedToASet = false;
			for (Set<Individual> disjointIndividualSet : allDisjointIndividualSets) {
				boolean addToThisSet = true;
				Iterator<Individual> i = disjointIndividualSet.iterator();
				while (i.hasNext() && addToThisSet) {
					Individual indv2 = i.next();
					SameIndividualAssertion ia = new SameIndividualAssertion(
							indv1.getName(), indv2.getName()).toggleNegated();
					if (indv1 != indv2 && !getABox().contains(ia)) {
						addToThisSet = false;
					}
				}
				if (addToThisSet) {
					disjointIndividualSet.add(indv1);
					addedToASet = true;
				}
			}
			if (!addedToASet) {
				Set<Individual> newDisjointIndividualSet = new HashSet<Individual>();
				newDisjointIndividualSet.add(indv1);
				allDisjointIndividualSets.add(newDisjointIndividualSet);
			}
		}
		return allDisjointIndividualSets;
	}

	public boolean hasSetWithMinCardinality(int n) {
		boolean found = false;
		Set<Set<Individual>> allDisjointIndividualSets = new HashSet<Set<Individual>>();
		for (Iterator<Individual> i = getIndividuals().iterator(); i.hasNext()
				&& !found;) {
			Individual indv1 = i.next();
			boolean addedToASet = false;
			for (Iterator<Set<Individual>> j = allDisjointIndividualSets
					.iterator(); j.hasNext() && !found;) {
				Set<Individual> disjointIndividualSet = j.next();
				boolean addToThisSet = true;
				Iterator<Individual> k = disjointIndividualSet.iterator();
				while (k.hasNext() && addToThisSet) {
					Individual indv2 = k.next();
					SameIndividualAssertion ia = new SameIndividualAssertion(
							indv1.getName(), indv2.getName()).toggleNegated();
					if (indv1 != indv2 && !getABox().contains(ia)) {
						addToThisSet = false;
					}
				}
				if (addToThisSet) {
					disjointIndividualSet.add(indv1);
					addedToASet = true;
					if (isConstraintSatisfied(disjointIndividualSet, n)) {
						found = true;
						result = disjointIndividualSet;
					}
				}
			}
			if (!addedToASet) {
				Set<Individual> newDisjointIndividualSet = new HashSet<Individual>();
				newDisjointIndividualSet.add(indv1);
				allDisjointIndividualSets.add(newDisjointIndividualSet);
				if (isConstraintSatisfied(newDisjointIndividualSet, n)) {
					found = true;
					result = newDisjointIndividualSet;
				}
			}
		}
		return found;
	}

	private boolean isConstraintSatisfied(Set<Individual> individualSet, int n) {
		return individualSet.size() >= n;
	}
}
